package tr.edu.ege.kipler.satisfiability.completion.rules.dl;

import java.util.Iterator;

import tr.edu.ege.kipler.satisfiability.UnsatisfiableException;
import tr.edu.ege.kipler.satisfiability.blocking.BlockingStrategy;
import tr.edu.ege.kipler.satisfiability.container.ABox;
import tr.edu.ege.kipler.satisfiability.container.ConceptCategory;
import tr.edu.ege.kipler.satisfiability.container.WcsData;
import tr.edu.ege.kipler.satisfiability.container.operational.IndividualNameManager;
import tr.edu.ege.kipler.satisfiability.container.operational.RelatedIndividualWithTypeFilter;
import tr.edu.ege.kipler.syntax.Role;
import tr.edu.ege.kipler.syntax.atomicformula.ConceptAssertion;
import tr.edu.ege.kipler.syntax.atomicformula.ObjectRoleAssertion;
import tr.edu.ege.kipler.syntax.concept.Concept;
import tr.edu.ege.kipler.syntax.concept.RoleQuantification;

/**
 * 
 * @author İnanç Seylan
 *
 */
public class SomeValuesRule extends ABoxRule {
	private ABox aBox;

	private boolean applied, exhaustive;

	private BlockingStrategy blocking;

	private RelatedIndividualWithTypeFilter filter;

	public boolean isApplied() {
		return applied;
	}

	public SomeValuesRule(BlockingStrategy blocking,
			RelatedIndividualWithTypeFilter filter, boolean exhaustive) {
		setBlocking(blocking);
		setFilter(filter);
		setExhaustive(exhaustive);
	}

	public BlockingStrategy getBlocking() {
		return blocking;
	}

	public void setBlocking(BlockingStrategy blocking) {
		this.blocking = blocking;
	}

	public RelatedIndividualWithTypeFilter getFilter() {
		return filter;
	}

	public void setFilter(RelatedIndividualWithTypeFilter filterer) {
		this.filter = filterer;
	}

	public boolean isExhaustive() {
		return exhaustive;
	}

	public void setExhaustive(boolean exhaustive) {
		this.exhaustive = exhaustive;
	}

	@Override
	public void apply() throws UnsatisfiableException {
		applied = false;
		aBox = getWorld().getABox();
		if (!getBlocking().isBlocked(aBox, getIndividual().getName())) {
			for (Iterator<Concept> i = getIndividual().conceptIterator(
					ConceptCategory.SOME); i.hasNext()
					&& ((!isExhaustive() && !isApplied()) || isExhaustive());) {
				Concept concept = i.next();
				RoleQuantification rq = (RoleQuantification) concept;
				if (!alreadyHasNeighborWithType(rq.getRole(), rq.getConcept())) {
					WcsData wcsData = getWcs().getData();
					String newIndvName = IndividualNameManager.getInstance()
							.generateIndividualName();
					ObjectRoleAssertion or = new ObjectRoleAssertion(rq
							.getRole(), getIndividual().getName(), newIndvName);
					ConceptAssertion depFormula = new ConceptAssertion(rq,
							getIndividual().getName());
					wcsData.getDependencyManager().move(or, depFormula);
					aBox.add(or);
					ConceptAssertion newConAssert = new ConceptAssertion(rq
							.getConcept(), newIndvName);
					wcsData.getLogger().info(
							"WCS " + getWcs().getId()
									+ " Some values rule: Adding "
									+ newConAssert + " and " + or);
					wcsData.getDependencyManager().move(newConAssert,
							depFormula);
					aBox.add(newConAssert);
					applied = true;
				}
			}
		}
	}

	private boolean alreadyHasNeighborWithType(Role role, Concept concept) {
		RelatedIndividualWithTypeFilter filterer = getFilter();
		filterer.setABox(aBox);
		filterer.setIndividual(getIndividual());
		filterer.setRole(role);
		filterer.setConcept(concept);
		return filterer.contains();
	}

}
